// pages/study/study.js
Page({
  data: {
    sessionId: '', // 学习会话ID
    examName: '学习目标',
    daysLeft: 0,
    examDate: '',
    selectedStartTime: '9:30',
    selectedEndTime: '12:30',
    studyDuration: '3', // 学习时长（小时）
    currentTime: '06:19:34', // 当前时间
    currentUser: {
      name: '小明同学',
      avatar: '../../assets/icons/avatar-placeholder.png',
      isOnline: true,
      examName: '学习目标',
      daysLeft: 0,
      examDate: ''
    },
    matchedUser: {
      name: '小红同学',
      avatar: '../../assets/icons/avatar-placeholder.png',
      isOnline: true,
      examName: '学习伙伴目标',
      daysLeft: 0,
      examDate: ''
    },
    partnerId: '', // 学习伙伴ID
    heartbeatTimer: null, // 心跳定时器
    statusCheckTimer: null, // 状态检查定时器
    studyStatus: 'preparing', // 学习状态: preparing, studying, completed
    studyStartTime: 0, // 学习开始时间戳
    studyElapsedTime: '00:00:00', // 已学习时间
    studyTimer: null, // 学习计时器
    timeTimer: null, // 时间更新计时器
    actualStudyDuration: 0, // 实际学习时长（分钟）
    // 自定义导航栏相关数据（给出稳定的首帧默认值，避免抖动）
    navBarHeight: 88, // 导航栏总高度（首帧默认）
    menuTop: 44, // 胶囊距离顶部的距离（首帧默认）
    menuHeight: 32, // 胶囊高度（首帧默认）
    // 新的picker相关数据
    showRestPicker: false, // 是否显示休息时间选择器
    restPickerValue: [8], // picker默认值（索引8对应15分钟）
    restTimeOptions: [], // 休息时间选项数组（5-90分钟，间隔5分钟）
    selectedRestTime: 15, // 当前选择的休息时间
    showExitModal: false, // 是否显示退出确认弹窗
    exitReason: '', // 退出原因
    // 动画相关
    showEncourageAnimation: false, // 显示鼓励动画
    showBombAnimation: false, // 显示炸弹动画
    hearts: [], // 点赞飘心队列
    burstRings: [], // 点赞爆发环队列
    encourageAnchor: null, // 鼓励按钮中心点 { left, top }
    lastEncTs: 0, // 上次点击时间戳
    burstTimer: null // 双击喷发定时器
  },

  // 头像地址规范化，避免历史 /assets 路径导致 500
  normalizeAvatar(url) {
    if (!url) return '/static/icons/avatar-placeholder.png';
    if (typeof url === 'string' && url.indexOf('/assets/') === 0) {
      return '/static/icons/avatar-placeholder.png';
    }
    return url;
  },

  // 将 avatar 规范化为可显示的 https/本地占位图；cloud:// 转失败则回退占位
  async ensureHttpsAvatar(avatar) {
    try {
      const placeholder = '/static/icons/avatar-placeholder.png';
      if (!avatar || typeof avatar !== 'string') return placeholder;

      // 已是可显示的网络/本地格式
      if (/^https?:\/\//i.test(avatar) || avatar.indexOf('data:') === 0 || avatar.indexOf('/static/') === 0 || avatar.indexOf('wxfile://') === 0) {
        return avatar;
      }

      // cloud:// 转临时 https
      if (avatar.indexOf('cloud://') === 0) {
        try {
          const tf = await wx.cloud.getTempFileURL({ fileList: [avatar] });
          const list = (tf && tf.fileList) || [];
          if (list[0] && list[0].tempFileURL) {
            return list[0].tempFileURL;
          }
        } catch (e2) {
          console.warn('getTempFileURL 失败:', e2);
        }
        return placeholder;
      }

      // 其它未知格式一律回退占位，避免渲染报错
      return placeholder;
    } catch (e) {
      console.warn('ensureHttpsAvatar 转换失败:', e);
      return '/static/icons/avatar-placeholder.png';
    }
  },

  // 从本地缓存覆盖当前用户展示信息（昵称/头像），兼容字段 nickName/nickname 与 avatarUrl/avatar_url
  async applyCurrentUserFromCache() {
    try {
      const cached = wx.getStorageSync('userInfo') || null;
      if (!cached) return;
      const name = (cached.nickName || cached.nickname || cached.name || this.data.currentUser.name || '我') + '';
      let avatar = this.normalizeAvatar(cached.avatarUrl || cached.avatar_url || cached.avatar || this.data.currentUser.avatar);
      if (typeof avatar === 'string' && avatar.indexOf('cloud://') === 0) {
        try {
          avatar = await this.ensureHttpsAvatar(avatar);
        } catch (e2) {
          console.warn('ensureHttpsAvatar 转换失败:', e2);
        }
      }
      this.setData({
        currentUser: Object.assign({}, this.data.currentUser, { name, avatar })
      });
    } catch (e) {
      console.warn('读取本地 userInfo 失败:', e);
    }
  },

  onLoad(options) {
    console.log('学习页面加载，参数:', options);
    // 先计算自定义导航栏，避免首帧抖动（同步 API，可立即得到值）
    try { this.calculateNavBarHeight(); } catch (e) { console.warn('calculateNavBarHeight early call error:', e); }
    
    // 保存URL参数
    this.setData({
      studyRecordId: options.studyRecordId,
      selectedStartTime: options.startTime || '09:00',
      selectedEndTime: options.endTime || '12:00',
      studyDuration: options.duration || '3'
    });
    
    // 初始化休息时间选项
    this.initRestTimeOptions();
    
    // 设置picker默认值
    this.setData({
      restPickerValue: [8], // 默认选择45分钟（索引8）
      selectedRestTime: 45,
      showRestPicker: false
    });
    
    // 检查登录状态
    this.checkLoginStatus();
    
    // 加载学习记录数据 - 先加载数据，再初始化UI
    this.loadStudyRecord();
    
    // 注意：initData()被移到loadStudyRecord成功后调用，确保使用真实数据
  },

  // 初始化休息时间选项 - 5-90分钟，间隔5分钟
  initRestTimeOptions() {
    const timeOptions = [];
    for (let i = 5; i <= 90; i += 5) {
      timeOptions.push(i);
    }
    
    this.setData({
      restTimeOptions: timeOptions
    });
    console.log('初始化休息时间选项:', timeOptions);
  },

  // 休息按钮点击事件
  onTakeRest() {
    console.log('休息按钮被点击');
    // 确保休息时间选项已初始化
    if (!this.data.restTimeOptions || this.data.restTimeOptions.length === 0) {
      this.initRestTimeOptions();
    }
    this.showRestPicker();
  },

  // 显示休息时间选择器 - 使用picker组件
  showRestPicker() {
    console.log('显示休息时间选择器，选项范围:', this.data.restTimeOptions);
    
    // 如果选项为空，立即初始化
    if (!this.data.restTimeOptions || this.data.restTimeOptions.length === 0) {
      const timeOptions = [];
      for (let i = 5; i <= 90; i += 5) {
        timeOptions.push(i);
      }
      this.setData({
        restTimeOptions: timeOptions,
        restPickerValue: [8],
        selectedRestTime: timeOptions[8],
        showRestPicker: true
      });
      console.log('初始化并显示休息时间选项:', timeOptions);
    } else {
      const idx = (this.data.restPickerValue && this.data.restPickerValue[0]) || 0;
      const sel = (this.data.restTimeOptions && this.data.restTimeOptions.length) ? this.data.restTimeOptions[idx] : 15;
      this.setData({
        showRestPicker: true,
        selectedRestTime: sel
      });
    }
  },

  // 隐藏休息时间选择器
  hideRestPicker() {
    console.log('隐藏休息时间选择器');
    this.setData({
      showRestPicker: false
    });
  },

  // 防止点击穿透
  preventTap() {
    // 空函数，用于阻止事件冒泡
  },

  // 休息时间变更事件
  onRestTimeChange(e) {
    const value = e.detail.value[0];
    const selectedTime = this.data.restTimeOptions[value];
    console.log('选择休息时间变更:', selectedTime, '分钟');
    this.setData({
      restPickerValue: [value],
      selectedRestTime: selectedTime
    });
  },

  // 确认休息时间
  confirmRestTime() {
    const idx = (this.data.restPickerValue && this.data.restPickerValue[0]) || 0;
    const selectedTime = (this.data.restTimeOptions && this.data.restTimeOptions[idx]) || this.data.selectedRestTime || 15;
    console.log('确认休息时间:', selectedTime, '分钟');
    
    this.setData({
      showRestPicker: false,
      selectedRestTime: selectedTime
    });
    
    // 设置休息状态
    this.setData({
      isResting: true,
      restTime: selectedTime
    });
    
    // 跳转到督搭页面
    wx.switchTab({
      url: `/pages/index/index`,
      success: () => {
        console.log('成功跳转到督搭页面，休息时长:', selectedTime, '分钟');
        wx.showToast({
          title: `开始休息${selectedTime}分钟`,
          icon: 'success'
        });
      },
      fail: (err) => {
        console.error('跳转到督搭页面失败:', err);
        wx.showToast({
          title: '跳转失败',
          icon: 'none'
        });
      }
    });
  },

  onReady() {
    // 页面初次渲染完成
    try { this.measureEncourageBtn(); } catch (e) {}
    setTimeout(() => { try { this.measureEncourageBtn(); } catch (e2) {} }, 100);
    // 冗余启动在线状态轮询（若 onShow 未触发或早停）
    try {
      if (!this.data.statusCheckTimer) {
        console.log('onReady: 补偿启动状态检查');
        this.startStatusCheck();
      }
    } catch (e3) {
      console.warn('onReady startStatusCheck failed:', e3);
    }
  },

  onShow() {
    // 页面显示
    // 设置导航栏标题
    if (this.data.studyStatus === 'studying') {
      wx.setNavigationBarTitle({
        title: this.data.studyElapsedTime || '00:00:00'
      });
    } else {
      wx.setNavigationBarTitle({
        title: '督搭学习'
      });
    }
    
    // 覆盖当前用户头像/昵称为本地缓存中的真实值
    this.applyCurrentUserFromCache();
    
    // 重启“当前时间”计时器（用于未开始状态显示当前时间）
    this.startTimeTimer();
    
    // 启动心跳与在线状态轮询
    console.log('onShow: 准备启动状态检查');
    this.startHeartbeat();
    try { this.startStatusCheck(); } catch (e) {}

    // 若处于学习中但计时器未启动，恢复学习计时器
    if (this.data.studyStatus === 'studying' && !this.data.studyTimer) {
      this.startStudyTimer();
    }
  },

  onHide() {
    // 页面隐藏
    // 停止心跳和状态检查
    this.stopHeartbeat();
    this.stopStatusCheck();

    // 页面隐藏时停止学习计时器，避免影响其他页面导航栏标题
    if (this.data.studyTimer) {
      clearInterval(this.data.studyTimer);
      this.setData({ studyTimer: null });
    }
  },

  // 启动心跳定时器 - 每60秒上报一次 lastSeen（学习页专属）
  startHeartbeat() {
    try {
      this.stopHeartbeat();
      const tick = async () => {
        try {
          console.log('online ping(study): tick');
          const online = await this.sendHeartbeat(60000);
          const prev = this.data.currentUser && this.data.currentUser.isOnline;
          if (typeof online === 'boolean') {
            if (prev !== online) {
              console.log('online ping(study): change', prev, '=>', online);
            }
            this.setData({ 'currentUser.isOnline': online });
          } else {
            console.log('online ping(study): result', online);
          }
        } catch (e) {
          console.warn('online ping(study): error', e);
        }
      };
      // 首次立即执行一次
      tick();
      const timer = setInterval(tick, 60000);
      this.setData({ heartbeatTimer: timer });
      console.log('online ping(study): started(60s)');
    } catch (e) {
      console.warn('startHeartbeat failed:', e);
    }
  },
  
  // 停止心跳定时器
  stopHeartbeat() {
    if (this.data.heartbeatTimer) {
      clearInterval(this.data.heartbeatTimer);
      this.setData({
        heartbeatTimer: null
      });
      console.log('心跳定时器已停止');
    }
  },
  
  // 发送心跳：写入 lastSeen 并返回是否在线
  async sendHeartbeat(onlineThresholdMs = 60000) {
    try {
      const res = await wx.cloud.callFunction({
        name: 'getUserInfo',
        data: { ping: true, onlineThresholdMs }
      }).catch(e => ({ _err: e }));
      const d = res && res.result && res.result.data;
      if (!d) return null;
      if (typeof d.isOnline === 'boolean') return d.isOnline;
      if (typeof d.status === 'string') return d.status === 'online';
      const last = d.lastSeen || d.lastLoginTime;
      if (!last) return null;
      let ts = 0;
      try { ts = new Date(last).getTime(); } catch (_) {}
      return ts > 0 && (Date.now() - ts) <= onlineThresholdMs;
    } catch (e) {
      console.warn('sendHeartbeat failed:', e);
      return null;
    }
  },
  
  // 启动伙伴在线状态检查（每15秒轮询一次，仅查询对方）
  startStatusCheck() {
    try {
      this.stopStatusCheck();
      const runner = async () => {
        try {
          await this.checkPartnerStatus();
        } catch (e) {
          console.warn('checkPartnerStatus error:', e);
        }
      };
      // 首次立即执行一次
      runner();
      const timer = setInterval(runner, 15000);
      this.setData({ statusCheckTimer: timer });
      console.log('partner online: started(15s)');
    } catch (e) {
      console.warn('startStatusCheck 启动失败:', e);
    }
  },
  
  // 停止状态检查定时器
  stopStatusCheck() {
    if (this.data.statusCheckTimer) {
      clearInterval(this.data.statusCheckTimer);
      this.setData({ statusCheckTimer: null });
      console.log('状态检查定时器已停止');
    }
  },
  
  // 检查伙伴在线状态（仅查询对方；优先 isOnline/status，其次 lastSeen/lastLoginTime）
  async checkPartnerStatus() {
    try {
      const pid = this.data.partnerId;
      if (!pid) {
        console.log('partner online tick: skip, no partnerId');
        return;
      }
      const peerRes = await wx.cloud
        .callFunction({
          name: 'getUserInfo',
          data: { openid: pid, onlineThresholdMs: 60000 }
        })
        .catch((e) => ({ _err: e }));

      const computeOnline = (resp) => {
        const d = resp && resp.result && resp.result.data;
        if (!d) return null;
        if (typeof d.isOnline === 'boolean') return d.isOnline;
        if (typeof d.status === 'string') return d.status === 'online';
        const last = d.lastSeen || d.lastLoginTime;
        if (!last) return null;
        let ts = 0;
        try { ts = new Date(last).getTime(); } catch (_) {}
        return ts > 0 && (Date.now() - ts) <= 60000;
      };

      const online = computeOnline(peerRes);
      console.log('partner online tick: result', online);
      if (typeof online === 'boolean') {
        const prev = this.data.matchedUser && this.data.matchedUser.isOnline;
        if (prev !== online) {
          console.log('partner online tick: change', prev, '=>', online);
        }
        this.setData({ 'matchedUser.isOnline': online });
      }
    } catch (e) {
      console.warn('checkPartnerStatus 失败:', e);
    }
  },

  // 加载学习记录数据
  async loadStudyRecord() {
    if (!this.data.studyRecordId) {
      console.error('缺少学习记录ID');
      wx.showToast({
        title: '学习记录不存在',
        icon: 'none'
      });
      setTimeout(() => {
        wx.navigateBack();
      }, 2000);
      return;
    }
    
    try {
      // wx.showLoading({ title: '加载中...' }); // 渐进式渲染：不使用全屏遮罩
      
      console.log(`尝试加载学习记录，ID: ${this.data.studyRecordId}`);
      console.log(`studyRecordId类型: ${typeof this.data.studyRecordId}, 长度: ${this.data.studyRecordId ? this.data.studyRecordId.length : 'undefined'}`);
      
      // 确保studyRecordId有效
      if (!this.data.studyRecordId || this.data.studyRecordId === 'undefined' || this.data.studyRecordId === 'null') {
        console.error('无效的学习记录ID:', this.data.studyRecordId);
        wx.showModal({
          title: '参数错误',
          content: '学习记录ID无效，请重新开始学习',
          showCancel: false,
          success: () => {
            wx.navigateBack();
          }
        });
        return;
      }
      
      // 使用正式的getStudyRecord云函数，不再使用调试版本
      const result = await wx.cloud.callFunction({
        name: 'getStudyRecord',
        data: {
          studyRecordId: this.data.studyRecordId
        }
      });
      
      console.log('getStudyRecord返回结果:', result.result);
      
      if (result.result.code === 0 && result.result.data) {
        const studyRecord = result.result.data;
        console.log('获取到学习记录:', studyRecord);
        
        // 保存伙伴ID，用于后续获取伙伴目标和在线状态
        this.setData({
          partnerId: studyRecord.partnerId || ''
        });
        
        // 获取伙伴在线状态
        const partnerIsOnline = studyRecord.partnerInfo && 
                               (studyRecord.partnerInfo.isOnline === true || 
                                studyRecord.partnerInfo.status === 'online');
        
        console.log('伙伴在线状态:', partnerIsOnline);
        
        // 更新页面基础数据（头像先规范化，再将 cloud:// 转临时 https）
        const rawMatchedAvatar = this.normalizeAvatar(studyRecord.partnerInfo?.avatarUrl || studyRecord.partnerInfo?.avatar_url || studyRecord.partnerInfo?.avatar);
        const rawCurrentAvatar = this.normalizeAvatar(studyRecord.userInfo?.avatarUrl || studyRecord.userInfo?.avatar_url || wx.getStorageSync('userInfo')?.avatarUrl || wx.getStorageSync('userInfo')?.avatar_url);
        let matchedAvatar = rawMatchedAvatar;
        let currentAvatar = rawCurrentAvatar;
        try { matchedAvatar = await this.ensureHttpsAvatar(rawMatchedAvatar); } catch (e) { console.warn('ensureHttpsAvatar(matched) 失败:', e); }
        try { currentAvatar = await this.ensureHttpsAvatar(rawCurrentAvatar); } catch (e) { console.warn('ensureHttpsAvatar(current) 失败:', e); }

        // 名称优先级：当前用户优先本地缓存，其次后端；对方优先后端
        const cached = wx.getStorageSync('userInfo') || {};
        const currentName = (cached.nickName || cached.nickname || cached.name || studyRecord.userInfo?.nickName || studyRecord.userInfo?.nickname || '我') + '';
        const matchedName = (studyRecord.partnerInfo && (studyRecord.partnerInfo.nickName || studyRecord.partnerInfo.nickname)) || '学习伙伴';

        this.setData({
          selectedStartTime: studyRecord.startTime || this.data.selectedStartTime,
          selectedEndTime: studyRecord.endTime || this.data.selectedEndTime,
          studyDuration: studyRecord.duration || this.data.studyDuration,
          matchId: studyRecord.matchId || this.data.matchId || null,
          partnerNick: matchedName, // 保存对方真实昵称，避免后续被占位覆盖
          'matchedUser.name': matchedName,
          'matchedUser.avatar': matchedAvatar || '/static/icons/avatar-placeholder.png',
          'matchedUser.isOnline': partnerIsOnline,
          'currentUser.name': currentName,
          'currentUser.avatar': currentAvatar || '/static/icons/avatar-placeholder.png'
        });
        console.log('首帧设置 matchedUser.name =', matchedName, '，当前data值 =', (this.data.matchedUser && this.data.matchedUser.name));

        // 基于 matchId 的兜底：再拉一遍对端资料覆盖昵称与头像（处理时序与老数据）
        if (studyRecord.matchId) {
          await this.ensurePeerInfoByMatchIdWithRetry(studyRecord.matchId);
          console.log('兜底后 matchedUser.name =', (this.data.matchedUser && this.data.matchedUser.name));
        }
        // 兜底完成后再用本地缓存覆盖一次当前用户，避免被后端默认“我”回写
        await this.applyCurrentUserFromCache();
        
        // 伙伴信息兜底补全（若缺失昵称或头像则拉取）
        this.ensurePartnerInfoCompleteness();
        
        // 启动状态检查（不依赖 partnerId，checkPartnerStatus 内部兜底）
        this.startStatusCheck();
        // 并行获取双方目标（参数透传）
        await this.loadBothGoals(this.data.partnerId, this.data.studyRecordId);
        
        // wx.hideLoading(); // 渐进式渲染：不使用全屏遮罩
        
        // 初始化UI数据 - 移到数据加载成功后
        this.initData();
        
        // 如果学习记录状态是已开始，恢复学习状态
        if (studyRecord.status === 'started' && studyRecord.actualStartTime) {
          const startTime = new Date(studyRecord.actualStartTime).getTime();
          this.setData({
            studyStatus: 'studying',
            studyStartTime: startTime
          });
          this.startStudyTimer();
        }
        
      } else {
        // wx.hideLoading(); // 渐进式渲染：不使用全屏遮罩
        console.error('获取学习记录失败:', result.result.message);
        console.error('完整错误信息:', result.result);
        
        // 显示详细的错误信息
        let errorMessage = result.result.message || '获取学习记录失败';
        if (result.result.error) {
          errorMessage += `\n详细错误: ${result.result.error}`;
        }
        
        wx.showModal({
          title: '获取学习记录失败',
          content: errorMessage,
          showCancel: false,
          success: () => {
            wx.navigateBack();
          }
        });
      }
    } catch (error) {
      // wx.hideLoading(); // 渐进式渲染：不使用全屏遮罩
      console.error('加载学习记录出错:', error);
      console.error('错误详情:', {
        message: error.message,
        errMsg: error.errMsg,
        studyRecordId: this.data.studyRecordId
      });
      
      // 显示详细的网络错误信息
      let errorMessage = '网络连接失败';
      if (error.errMsg) {
        errorMessage += `\n错误信息: ${error.errMsg}`;
      } else if (error.message) {
        errorMessage += `\n错误信息: ${error.message}`;
      }
      
      wx.showModal({
        title: '网络错误',
        content: errorMessage,
        showCancel: false,
        success: () => {
          wx.navigateBack();
        }
      });
    }
  },
  
  // 并行加载双方目标（参数透传，避免依赖 this.data 的异步时序）
  async loadBothGoals(partnerId, studyRecordId) {
    try {
      console.log('开始并行加载双方目标', { partnerId, studyRecordId });
      
      // 并行请求双方目标
      const [myGoalResult, partnerGoalResult] = await Promise.all([
        this.loadMyGoal(),
        this.loadPartnerGoal(partnerId, studyRecordId)
      ]);
      
      console.log('双方目标加载完成:', {
        myGoal: myGoalResult,
        partnerGoal: partnerGoalResult
      });
      
      // 更新UI
      this.updateGoalsUI(myGoalResult, partnerGoalResult);
      // 最终兜底：如果昵称仍是占位，则用首帧保存的 partnerNick 回填
      if (
        this.data &&
        this.data.partnerNick &&
        this.data.matchedUser &&
        (this.data.matchedUser.name === '学习伙伴' || !this.data.matchedUser.name)
      ) {
        this.setData({ 'matchedUser.name': this.data.partnerNick });
        console.log('finalize: 回填对方昵称为 partnerNick =', this.data.partnerNick);
      }
      
    } catch (error) {
      console.error('加载双方目标出错:', error);
    }
  },
  
  // 加载我的目标
  async loadMyGoal() {
    try {
      console.log('加载我的目标');
      const result = await wx.cloud.callFunction({
        name: 'manageGoal',
        data: {
          action: 'get'
        }
      });
      
      if (result.result.code === 0) {
        return result.result.data;
      } else {
        console.error('获取我的目标失败:', result.result.msg);
        return null;
      }
    } catch (error) {
      console.error('加载我的目标出错:', error);
      return null;
    }
  },
  
  // 加载伙伴目标（支持仅凭 studyRecordId 反查，不再强制两者同时存在）
  async loadPartnerGoal(partnerId, studyRecordId) {
    const pid = partnerId || this.data.partnerId;
    const srid = studyRecordId || this.data.studyRecordId;

    // 允许仅凭 studyRecordId 反查伙伴
    if (!pid && !srid) {
      console.log('缺少 partnerId 与 studyRecordId，无法加载伙伴目标', { pid, srid });
      return null;
    }
    
    try {
      const payload = {};
      if (pid) payload.partnerId = pid;
      if (srid) payload.studyRecordId = srid;

      console.log('加载伙伴目标，入参:', payload);
      const result = await wx.cloud.callFunction({
        name: 'getPartnerGoal',
        data: payload
      });
      
      if (result.result.code === 0) {
        return result.result.data;
      } else {
        console.error('获取伙伴目标失败:', result.result.message);
        return null;
      }
    } catch (error) {
      console.error('加载伙伴目标出错:', error);
      return null;
    }
  },
  
  // 更新目标UI
  updateGoalsUI(myGoal, partnerGoal) {
    // 处理我的目标
    if (myGoal) {
      // 计算剩余天数
      let myDaysLeft = 0;
      if (myGoal.deadline) {
        const deadline = new Date(myGoal.deadline);
        const today = new Date();
        const timeDiff = deadline.getTime() - today.getTime();
        myDaysLeft = Math.ceil(timeDiff / (1000 * 3600 * 24));
        myDaysLeft = myDaysLeft > 0 ? myDaysLeft : 0;
      }
      
      // 格式化日期
      let formattedDeadline = '';
      if (myGoal.deadline) {
        const deadline = new Date(myGoal.deadline);
        formattedDeadline = `${deadline.getFullYear()}年${deadline.getMonth() + 1}月${deadline.getDate()}日`;
      }
      
      this.setData({
        examName: myGoal.title || '学习目标',
        daysLeft: myDaysLeft,
        examDate: formattedDeadline,
        'currentUser.examName': myGoal.title || '学习目标',
        'currentUser.daysLeft': myDaysLeft,
        'currentUser.examDate': formattedDeadline
      });
    } else {
      // 没有目标时使用默认值
      this.setData({
        examName: '学习目标',
        daysLeft: 0,
        examDate: '',
        'currentUser.examName': '学习目标',
        'currentUser.daysLeft': 0,
        'currentUser.examDate': ''
      });
    }
    
    // 处理伙伴目标
    if (partnerGoal) {
      // 格式化日期
      let formattedDeadline = '';
      if (partnerGoal.deadline) {
        const deadline = new Date(partnerGoal.deadline);
        formattedDeadline = `${deadline.getFullYear()}年${deadline.getMonth() + 1}月${deadline.getDate()}日`;
      }
      
      const updates = {
        'matchedUser.examName': partnerGoal.title || '学习伙伴目标',
        'matchedUser.daysLeft': partnerGoal.daysLeft || 0,
        'matchedUser.examDate': formattedDeadline
      };
      // 仅当云端明确给出昵称时才覆盖，避免把“学习伙伴”回写
      let hasNick = false;
      if (partnerGoal.partnerInfo) {
        const nick = partnerGoal.partnerInfo.nickName || partnerGoal.partnerInfo.nickname;
        if (nick) {
          updates['matchedUser.name'] = nick;
          hasNick = true;
        }
        // 头像不在此处覆盖，避免将 cloud:// 或占位覆盖回去
      }
      this.setData(updates);
      if (!hasNick && this.data.partnerNick && ((this.data.matchedUser && this.data.matchedUser.name === '学习伙伴') || !this.data.matchedUser || !this.data.matchedUser.name)) {
        this.setData({ 'matchedUser.name': this.data.partnerNick });
        console.log('updateGoalsUI 无昵称，回填 partnerNick =', this.data.partnerNick);
      }
      console.log('updateGoalsUI 完成，matchedUser.name:', this.data.matchedUser && this.data.matchedUser.name);
    } else {
      // 没有目标时使用默认值
      this.setData({
        'matchedUser.examName': '学习伙伴目标',
        'matchedUser.daysLeft': 0,
        'matchedUser.examDate': ''
      });
    }
    
    console.log('目标UI已更新:', {
      currentUser: this.data.currentUser,
      matchedUser: this.data.matchedUser
    });
  },

  // 计算真实的考试剩余天数
  calculateRealDaysLeft() {
    // 2025年12月21日CET-6考试
    const examDate = new Date('2025-12-21T00:00:00');
    const today = new Date();
    
    // 输出日期信息用于调试
    console.log('考试日期:', examDate.toISOString());
    console.log('今天日期:', today.toISOString());
    
    const timeDiff = examDate.getTime() - today.getTime();
    const daysLeft = Math.ceil(timeDiff / (1000 * 3600 * 24));
    
    console.log('计算的考试剩余天数:', daysLeft);
    return daysLeft > 0 ? daysLeft : 0;
  },

  // 加载用户信息（保留作为备用）
  loadUserInfo() {
    const userInfo = wx.getStorageSync('userInfo');
    
    if (userInfo) {
      this.setData({
        currentUser: {
          name: userInfo.nickName || userInfo.nickname || '我',
          avatar: this.normalizeAvatar(userInfo.avatarUrl || userInfo.avatar_url),
          isOnline: true,
          examName: 'CET-6',
          daysLeft: this.data.daysLeft,
          examDate: this.data.examDate
        }
      });
    }
  },

  // 伙伴信息补全：若 matchedUser 昵称或头像缺失，则用 partnerId 拉取云端资料兜底
  async ensurePartnerInfoCompleteness() {
    try {
      const needFetch = (!this.data.matchedUser.name || this.data.matchedUser.name === '学习伙伴') ||
                        (!this.data.matchedUser.avatar || String(this.data.matchedUser.avatar).indexOf('avatar-placeholder') !== -1);
      if (!needFetch) return;
      if (!this.data.partnerId) return;
      const result = await wx.cloud.callFunction({
        name: 'getUserInfo',
        data: { openid: this.data.partnerId }
      });
      if (result.result && result.result.code === 0 && result.result.data) {
        const info = result.result.data;
        const name = info.nickName || info.nickname || this.data.matchedUser.name || '学习伙伴';
        let avatar = this.normalizeAvatar(info.avatarUrl || info.avatar_url || this.data.matchedUser.avatar);
        try {
          avatar = await this.ensureHttpsAvatar(avatar);
        } catch (e2) {
          console.warn('ensureHttpsAvatar 转换失败:', e2);
        }
        const updates = { 'matchedUser.name': name };
        if (
          avatar &&
          typeof avatar === 'string' &&
          (/^https?:\/\//i.test(avatar) ||
            avatar.indexOf('/static/') === 0 ||
            avatar.indexOf('wxfile://') === 0 ||
            avatar.indexOf('data:') === 0)
        ) {
          updates['matchedUser.avatar'] = avatar;
        } else {
          updates['matchedUser.avatar'] = '/static/icons/avatar-placeholder.png';
        }
        this.setData(updates);
      }
    } catch (e) {
      console.warn('补全伙伴信息失败:', e);
    }
  },

  // 更新当前时间
  updateCurrentTime() {
    const now = new Date();
    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');
    const timeStr = `${hours}:${minutes}:${seconds}`;
    
    this.setData({
      currentTime: timeStr
    });
  },

  // 学习页头像加载失败兜底（对方）
  onMatchedAvatarError(e) {
    const url = (e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.avatar) || '';
    const err = (e && e.detail && e.detail.errMsg) || '';
    console.warn('matchedUser avatar load error:', err, 'url:', url);
    this.setData({ 'matchedUser.avatar': '/static/icons/avatar-placeholder.png' });
  },

  onMatchedAvatarLoad(e) {
    const url = (e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.avatar) || '';
    console.log('matchedUser avatar loaded:', url);
  },

  // 当前用户头像加载失败兜底：占位并尝试刷新为新临时链接
  async onCurrentAvatarError(e) {
    const url = (e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.avatar) || '';
    const err = (e && e.detail && e.detail.errMsg) || '';
    console.warn('currentUser avatar load error:', err, 'url:', url);
    // 先回落占位，避免空白
    this.setData({ 'currentUser.avatar': '/static/icons/avatar-placeholder.png' });
    // 异步刷新头像（云端 fileID -> 新临时 https；或使用缓存头像）
    try {
      const refreshed = await this.refreshCurrentUserAvatar();
      if (refreshed) {
        this.setData({ 'currentUser.avatar': refreshed });
        console.log('currentUser avatar refreshed:', refreshed);
      } else {
        console.log('currentUser avatar refresh: no better url, keep placeholder');
      }
    } catch (e2) {
      console.warn('currentUser avatar refresh failed:', e2);
    }
  },

  // 刷新当前用户头像：优先云端 fileID 转新临时 https，其次使用本地缓存头像
  async refreshCurrentUserAvatar() {
    try {
      // 1) 尝试云函数获取最新头像与原始 fileID
      let cloudUrl = null;
      try {
        const res = await wx.cloud.callFunction({
          name: 'getUserInfo',
          data: { ping: false, onlineThresholdMs: 60000 }
        }).catch(e => ({ _err: e }));
        const d = res && res.result && res.result.data;
        if (d) {
          // 优先使用原始 fileID，保证拿到最新 temp URL
          const fileId = d.rawAvatarFileId || '';
          if (fileId && typeof fileId === 'string' && fileId.indexOf('cloud://') === 0) {
            try {
              const tf = await wx.cloud.getTempFileURL({ fileList: [fileId] });
              const list = (tf && tf.fileList) || [];
              if (list[0] && list[0].tempFileURL) {
                cloudUrl = list[0].tempFileURL;
              }
            } catch (e2) {
              console.warn('refreshCurrentUserAvatar: getTempFileURL by fileID failed:', e2);
            }
          }
          // 若无 fileID，退而取云端 avatarUrl/avatar_url
          if (!cloudUrl) {
            const avatarAny = d.avatarUrl || d.avatar_url || d.avatar || '';
            if (avatarAny) {
              cloudUrl = await this.ensureHttpsAvatar(this.normalizeAvatar(avatarAny));
            }
          }
        }
      } catch (e1) {
        console.warn('refreshCurrentUserAvatar: getUserInfo failed:', e1);
      }
      // 2) 如仍无可用链接，尝试使用本地缓存（可能是 wechat CDN 头像）
      if (!cloudUrl) {
        try {
          const cached = wx.getStorageSync('userInfo') || {};
          const c = cached.avatarUrl || cached.avatar_url || cached.avatar || '';
          if (c) {
            const norm = await this.ensureHttpsAvatar(this.normalizeAvatar(c));
            if (norm) cloudUrl = norm;
          }
        } catch (e3) {
          console.warn('refreshCurrentUserAvatar: read cache failed:', e3);
        }
      }
      // 验证为可显示的链接格式
      if (
        cloudUrl &&
        typeof cloudUrl === 'string' &&
        (/^https?:\/\//i.test(cloudUrl) ||
          cloudUrl.indexOf('/static/') === 0 ||
          cloudUrl.indexOf('wxfile://') === 0 ||
          cloudUrl.indexOf('data:') === 0)
      ) {
        return cloudUrl;
      }
      return null;
    } catch (e) {
      console.warn('refreshCurrentUserAvatar failed:', e);
      return null;
    }
  },

  // 基于 matchId 的兜底：查询对端资料并覆盖 matchedUser（含 cloud:// → https）
  async ensurePeerInfoByMatchId(matchId) {
    try {
      if (!matchId) return;
      let pi = null;

      try {
        const res = await wx.cloud.callFunction({
          name: 'getStudyRecord',
          data: { action: 'peerByMatchId', matchId }
        });
        if (res && res.result && res.result.code === 0 && res.result.data) {
          // 保存对端 openid 作为 partnerId，便于在线轮询
          const peerUserId = res.result.data.peerStudyRecord && (res.result.data.peerStudyRecord.userId || res.result.data.peerStudyRecord._openid);
          if (peerUserId && !this.data.partnerId) {
            this.setData({ partnerId: peerUserId });
            console.log('ensurePeerInfoByMatchId: 设置 partnerId =', peerUserId);
          }
          if (res.result.data.partnerInfo) {
            pi = res.result.data.partnerInfo;
          }
        }
      } catch (e1) {
        console.warn('getStudyRecord peerByMatchId 调用失败:', e1);
      }

      if (pi) {
        const updates = {};
        // 仅当云端返回了非空昵称时才覆盖，避免回写占位“学习伙伴”
        const newName = pi.nickName || pi.nickname;
        if (newName) {
          updates['matchedUser.name'] = newName;
          updates['partnerNick'] = newName; // 同步保存真实昵称，防止被占位回写
        }
        // 头像仅在生成有效可显示链接时才覆盖
        let avatarCandidate = this.normalizeAvatar(pi.avatarUrl || pi.avatar_url || pi.avatar);
        try {
          avatarCandidate = await this.ensureHttpsAvatar(avatarCandidate);
        } catch (e3) {
          console.warn('ensureHttpsAvatar 转换失败:', e3);
        }
        if (
          avatarCandidate &&
          typeof avatarCandidate === 'string' &&
          (/^https?:\/\//i.test(avatarCandidate) ||
            avatarCandidate.indexOf('/static/') === 0 ||
            avatarCandidate.indexOf('wxfile://') === 0 ||
            avatarCandidate.indexOf('data:') === 0)
        ) {
          updates['matchedUser.avatar'] = avatarCandidate;
        }
        if (Object.keys(updates).length > 0) {
          this.setData(updates);
        }
      }
    } catch (e) {
      console.warn('ensurePeerInfoByMatchId 失败:', e);
    }
  },

  // 带重试的兜底：处理对端记录/资料稍后才就绪的场景
  async ensurePeerInfoByMatchIdWithRetry(matchId) {
    try {
      const delays = [800, 1500, 2500];
      for (let i = 0; i < delays.length; i++) {
        await this.ensurePeerInfoByMatchId(matchId);
        const nameIsDefault = !this.data.matchedUser || !this.data.matchedUser.name || this.data.matchedUser.name === '学习伙伴';
        const avatarIsDefault = !this.data.matchedUser || !this.data.matchedUser.avatar || String(this.data.matchedUser.avatar).indexOf('avatar-placeholder') !== -1;
        if (!nameIsDefault && !avatarIsDefault) return;
        await new Promise((r) => setTimeout(r, delays[i]));
      }
      // 仍未获取到真实资料，维持占位
    } catch (e) {
      console.warn('ensurePeerInfoByMatchIdWithRetry 失败:', e);
    }
  },

  // 启动时间更新定时器
  startTimeTimer() {
    // 清除之前的定时器
    if (this.data.timeTimer) {
      clearInterval(this.data.timeTimer);
    }
    
    // 立即更新一次时间
    this.updateCurrentTime();
    
    // 启动定时器，每秒更新一次
    const timer = setInterval(() => {
      this.updateCurrentTime();
    }, 1000);
    
    this.setData({
      timeTimer: timer
    });
  },

  onUnload() {
    // 页面卸载时清理所有计时器
    if (this.data.studyTimer) {
      clearInterval(this.data.studyTimer);
    }
    if (this.data.timeTimer) {
      clearInterval(this.data.timeTimer);
    }
    this.stopHeartbeat();
    this.stopStatusCheck();
  },

  // 处理导航栏返回按钮
  onNavigationBarBackTap() {
    if (this.data.isStudying) {
      // 如果正在学习，弹出确认对话框
      wx.showModal({
        title: '退出学习',
        content: '确定要退出当前学习吗？',
        success: (res) => {
          if (res.confirm) {
            this.exitStudy();
            wx.navigateBack();
          }
        }
      });
    } else {
      wx.navigateBack();
    }
  },



  // 初始化数据
  initData() {
    // 生成学习会话ID
    const sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    this.setData({
      sessionId: sessionId
    });
    
    // 计算自定义导航栏高度
    this.calculateNavBarHeight();
    
    // 更新当前时间
    this.updateCurrentTime();
    
    // 开始时间计时器
    this.startTimeTimer();
    
    // 输出当前页面数据状态
    console.log('页面数据初始化完成:', {
      selectedStartTime: this.data.selectedStartTime,
      selectedEndTime: this.data.selectedEndTime,
      studyDuration: this.data.studyDuration,
      daysLeft: this.data.daysLeft,
      currentUser: this.data.currentUser,
      matchedUser: this.data.matchedUser
    });
    
    // 立即开始学习
    this.startStudySession();
  },

  // 计算剩余天数
  calculateDaysLeft() {
    const examDate = new Date('2025-07-09');
    const today = new Date();
    const timeDiff = examDate.getTime() - today.getTime();
    const daysLeft = Math.ceil(timeDiff / (1000 * 3600 * 24));
    
    this.setData({
      daysLeft: daysLeft > 0 ? daysLeft : 0
    });
  },

  // 计算自定义导航栏高度
  calculateNavBarHeight() {
    try {
      // 获取系统信息 - 使用新的API替代已弃用的wx.getSystemInfoSync
      const systemInfo = wx.getWindowInfo();
      // 获取胶囊按钮位置信息
      const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
      
      // 导航栏高度 = 状态栏到胶囊的间距（胶囊上坐标位置-状态栏高度） * 2 + 胶囊高度 + 状态栏高度
      const navBarHeight = (menuButtonInfo.top - systemInfo.statusBarHeight) * 2 + menuButtonInfo.height + systemInfo.statusBarHeight;
      
      this.setData({
        navBarHeight: navBarHeight,
        menuTop: menuButtonInfo.top,
        menuHeight: menuButtonInfo.height
      });
    } catch (error) {
      console.error('计算导航栏高度失败:', error);
      // 设置默认值
      this.setData({
        navBarHeight: 88,
        menuTop: 44,
        menuHeight: 32
      });
    }
  },










  // 开始学习会话
  async startStudySession() {
    console.log('开始学习会话');
    
    if (!this.data.studyRecordId) {
      wx.showToast({
        title: '学习记录不存在',
        icon: 'none'
      });
      return;
    }
    
    try {
      // wx.showLoading({ title: '开始学习...' }); // 渐进式渲染：不使用全屏遮罩
      
      console.log(`尝试更新学习记录状态，ID: ${this.data.studyRecordId}`);
      
      // 调用云函数更新学习记录状态为已开始
      const result = await wx.cloud.callFunction({
        name: 'updateStudyRecord',
        data: {
          studyRecordId: this.data.studyRecordId,
          status: 'started',
          actualStartTime: new Date()
        }
      });
      
      console.log('updateStudyRecord返回结果:', result.result);
      
      // wx.hideLoading(); // 渐进式渲染：不使用全屏遮罩
      
      if (result.result.code === 0) {
        console.log('学习记录状态更新成功');
        
        this.setData({
          studyStatus: 'studying',
          studyStartTime: new Date().getTime(),
          studyElapsedTime: '00:00:00'
        });
        
        // 设置导航栏标题为初始时间
        wx.setNavigationBarTitle({
          title: '00:00:00'
        });
        
        // 开始学习计时器
        this.startStudyTimer();
        
        wx.showToast({
          title: '开始学习！',
          icon: 'success',
          duration: 1500
        });
      } else {
        console.error('更新学习记录失败:', result.result.message);
        wx.showToast({
          title: result.result.message || '开始学习失败',
          icon: 'none'
        });
      }
    } catch (error) {
      // wx.hideLoading(); // 渐进式渲染：不使用全屏遮罩
      console.error('开始学习会话失败:', error);
      wx.showToast({
        title: '网络错误，请重试',
        icon: 'none'
      });
    }
  },

  // 开始学习计时
  startStudyTimer() {
    // 避免重复计时器
    if (this.data.studyTimer) {
      clearInterval(this.data.studyTimer);
      this.setData({ studyTimer: null });
    }

    const timer = setInterval(() => {
      const now = Date.now();
      const elapsed = now - this.data.studyStartTime;
      const hours = Math.floor(elapsed / (1000 * 60 * 60));
      const minutes = Math.floor((elapsed % (1000 * 60 * 60)) / (1000 * 60));
      const seconds = Math.floor((elapsed % (1000 * 60)) / 1000);
      
      const timeStr = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
      
      this.setData({
        studyElapsedTime: timeStr
      });
      
      // 仅当当前顶部页面是学习页时才更新导航栏标题
      const pages = getCurrentPages && getCurrentPages();
      const current = pages && pages[pages.length - 1];
      if (current && (current.route === 'pages/study/study' || current.__route__ === 'pages/study/study')) {
        wx.setNavigationBarTitle({
          title: timeStr
        });
      }
    }, 1000);

    this.setData({ studyTimer: timer });
  },

  // 结束学习
  async endStudy() {
    console.log('结束学习');
    
    if (!this.data.studyRecordId) {
      wx.navigateBack();
      return;
    }
    
    // 停止学习计时器
    if (this.data.studyTimer) {
      clearInterval(this.data.studyTimer);
    }
    
    // 停止心跳和状态检查定时器
    this.stopHeartbeat();
    this.stopStatusCheck();
    
    // 计算实际学习时长
    const actualDuration = Math.floor((new Date().getTime() - this.data.studyStartTime) / 1000 / 60); // 分钟
    
    try {
      wx.showLoading({ title: '结束学习...' });
      
      // 调用云函数更新学习记录状态为已完成
      const result = await wx.cloud.callFunction({
        name: 'updateStudyRecord',
        data: {
          studyRecordId: this.data.studyRecordId,
          status: 'completed',
          actualEndTime: new Date(),
          actualDuration: actualDuration,
          focusScore: Math.min(100, Math.max(60, 100 - Math.floor(actualDuration / 10))) // 简单的专注度评分
        }
      });
      
      wx.hideLoading();
      
      if (result.result.code === 0) {
        console.log('学习记录更新成功，实际学习时长:', actualDuration, '分钟');
        
        this.setData({
          studyStatus: 'completed',
          actualStudyDuration: actualDuration
        });
        
        wx.showModal({
          title: '学习完成',
          content: `恭喜！您已完成 ${actualDuration} 分钟的学习`,
          showCancel: false,
          success: () => {
            // 返回首页
            wx.navigateBack();
          }
        });
      } else {
        console.error('更新学习记录失败:', result.result.message);
        // 即使更新失败，也允许用户返回
        wx.showModal({
          title: '学习完成',
          content: `您已完成 ${actualDuration} 分钟的学习`,
          showCancel: false,
          success: () => {
            wx.navigateBack();
          }
        });
      }
    } catch (error) {
      wx.hideLoading();
      console.error('结束学习失败:', error);
      // 即使出错，也允许用户返回
      wx.showModal({
        title: '学习完成',
        content: `您已完成学习`,
        showCancel: false,
        success: () => {
          wx.navigateBack();
        }
      });
    }
  },

  // 显示退出确认弹窗 - 使用自定义弹窗
  showExitModal() {
    this.setData({
      showExitModal: true
    });
  },

  // 隐藏退出确认弹窗
  hideExitModal() {
    this.setData({
      showExitModal: false,
      exitReason: ''
    });
  },

  // 处理退出原因输入
  onExitReasonInput(e) {
    this.setData({
      exitReason: e.detail.value
    });
  },

  // 确认退出（取消本次学习）
  async confirmExit() {
    console.log('确认退出学习');

    // 检查退出原因是否为空
    if (!this.data.exitReason || this.data.exitReason.trim() === '') {
      wx.showToast({
        title: '请填写退出原因',
        icon: 'none',
        duration: 2000
      });
      return;
    }

    // 隐藏弹窗
    this.setData({
      showExitModal: false
    });

    try {
      wx.showLoading({ title: '退出学习...' });

      // 计算实际学习时长
      const actualDuration = this.data.studyStartTime
        ? Math.floor((Date.now() - this.data.studyStartTime) / 1000 / 60)
        : 0;

      // 如果有学习记录ID，更新学习记录状态
      if (this.data.studyRecordId) {
        const result = await wx.cloud.callFunction({
          name: 'updateStudyRecord',
          data: {
            studyRecordId: this.data.studyRecordId,
            status: 'cancelled',
            actualEndTime: new Date(),
            actualDuration: actualDuration,
            exitReason: this.data.exitReason.trim()
          }
        });

        if (result.result.code === 0) {
          console.log(`学习记录已更新为取消状态，实际学习时长: ${actualDuration}分钟，退出原因: ${this.data.exitReason}`);
        } else {
          console.error('更新学习记录失败:', result.result.message);
        }
      }
    } catch (error) {
      console.error('退出学习处理失败:', error);
    } finally {
      wx.hideLoading();

      // 停止所有计时器与心跳/状态检查
      if (this.data.studyTimer) {
        clearInterval(this.data.studyTimer);
      }
      if (this.data.timeTimer) {
        clearInterval(this.data.timeTimer);
      }
      this.stopHeartbeat();
      this.stopStatusCheck();

      // 返回首页
      wx.switchTab({
        url: '/pages/index/index'
      });
    }
  },

  // 退出学习（显示退出确认弹窗）
  exitStudy() {
    this.setData({
      showExitModal: true
    });
  },

  // 发送鼓励 - 模拟版本
  async sendEncouragement() {
    console.log('模拟发送鼓励');
    try {
      await new Promise((resolve) => setTimeout(resolve, 300));
      console.log('鼓励已发送');
    } catch (error) {
      console.error('发送鼓励失败:', error);
    }
  },

  // 测量鼓励按钮中心点
  measureEncourageBtn() {
    try {
      const q = wx.createSelectorQuery();
      q.select('#encourageBtn').boundingClientRect(rect => {
        if (rect) {
          const left = rect.left + rect.width / 2;
          const top = rect.top + rect.height / 2;
          this.setData({ encourageAnchor: { left, top } });
        }
      }).exec();
    } catch (e) {
      console.warn('measureEncourageBtn 失败:', e);
    }
  },

  // 生成爆发环（按钮中心500ms扩散）
  spawnBurstRing() {
    try {
      const anchor = this.data.encourageAnchor;
      if (!anchor) return;
      const id = 'r' + Date.now() + Math.floor(Math.random() * 1000);
      const ring = { id, left: anchor.left - 30, top: anchor.top - 30 }; // 初始左上角，60px圆
      const list = (this.data.burstRings || []).concat(ring);
      this.setData({ burstRings: list });
      setTimeout(() => {
        const remain = (this.data.burstRings || []).filter(x => x.id !== id);
        this.setData({ burstRings: remain });
      }, 520);
    } catch (e) {
      console.warn('spawnBurstRing 失败:', e);
    }
  },

  // 生成抖音风格点赞飘心（混合文本/图标）
  spawnHearts(e, amount) {
    try {
      const colors = ['#ff0050', '#ff3c80', '#ff75a9', '#ffd166', '#6ecbff', '#9aff6e'];
      const texts = ['点赞', '+1', 'Nice!'];
      const count = typeof amount === 'number' ? amount : (Math.floor(Math.random() * 3) + 6); // 6-8
      const batchId = 'h' + Date.now() + Math.floor(Math.random() * 1000);

      // 计算锚点
      let baseX;
      let baseY;
      const d = (e && e.detail) || {};
      if (typeof d.x === 'number' && typeof d.y === 'number') {
        baseX = d.x;
        baseY = d.y;
      } else if (this.data.encourageAnchor) {
        baseX = this.data.encourageAnchor.left;
        baseY = this.data.encourageAnchor.top;
      } else {
        try {
          const si = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync();
          baseX = (si.windowWidth || 375) / 2;
          baseY = (si.windowHeight || 667) - 100;
        } catch (_) {
          baseX = 180; baseY = 600;
        }
      }

      const hearts = [];
      for (let i = 0; i < count; i++) {
        const isText = Math.random() < 0.3;
        const size = isText ? (Math.floor(Math.random() * 29) + 12) : (Math.floor(Math.random() * 35) + 14); // text 12-40, icon 14-48
        const color = colors[Math.floor(Math.random() * colors.length)];
        const duration = Number((Math.random() * 0.5 + 1.0).toFixed(2)); // 1.0 - 1.5
        const delay = Number((Math.random() * 0.15).toFixed(2)); // 0 - 0.15
        const offsetX = Math.floor(Math.random() * 100) - 50; // -50 ~ 50
        const id = `${batchId}_${i}`;
        hearts.push({
          id,
          left: baseX + offsetX,
          top: baseY - 20,
          size,
          color,
          duration,
          delay,
          type: isText ? 'text' : 'icon',
          content: isText ? texts[Math.floor(Math.random() * texts.length)] : '❤',
          batchId
        });
      }

      const newHearts = (this.data.hearts || []).concat(hearts);
      this.setData({ hearts: newHearts });

      const maxDuration = Math.max(...hearts.map(h => h.duration + h.delay));
      setTimeout(() => {
        const remain = (this.data.hearts || []).filter(h => h.batchId !== batchId);
        this.setData({ hearts: remain });
      }, Math.ceil((maxDuration + 0.2) * 1000));
    } catch (err) {
      console.warn('spawnHearts 执行失败:', err);
    }
  },

  // 鼓励按钮点击事件
  onEncourage(e) {
    const now = Date.now();
    const isDouble = (now - (this.data.lastEncTs || 0)) < 300;
    this.setData({ lastEncTs: now });

    // 测量锚点（偶发布局变化时兜底刷新）
    try { this.measureEncourageBtn(); } catch (_) {}

    // 单次点击粒子与爆发环
    try { this.spawnHearts(e, isDouble ? 10 : 6); } catch (err) { console.warn('spawnHearts error:', err); }
    try { this.spawnBurstRing(); } catch (err2) { console.warn('spawnBurstRing error:', err2); }

    // 双击 2s 喷发：每100ms 追加3粒子
    if (isDouble) {
      try {
        if (this.data.burstTimer) {
          clearInterval(this.data.burstTimer);
          this.setData({ burstTimer: null });
        }
        const timer = setInterval(() => {
          this.spawnHearts(null, 3);
        }, 100);
        this.setData({ burstTimer: timer });
        setTimeout(() => {
          if (this.data.burstTimer) {
            clearInterval(this.data.burstTimer);
            this.setData({ burstTimer: null });
          }
        }, 2000);
      } catch (e3) {
        console.warn('double-burst 启动失败:', e3);
      }
    }

    // 保留原业务逻辑
    this.sendEncouragement();
  },

  // 发送炸弹 - 模拟版本
  async sendBomb() {
    console.log('发送炸弹');
    try {
      await new Promise((resolve) => setTimeout(resolve, 300));
      console.log('炸弹已发送');
    } catch (error) {
      console.error('发送炸弹失败:', error);
    }
  },

  // 扔炸弹按钮点击事件
  onThrowBomb() {
    // 强烈触觉反馈
    wx.vibrateShort({
      type: 'heavy'
    });

    // 显示炸弹动画
    this.setData({
      showBombAnimation: true
    });

    // 1.2秒后隐藏动画
    setTimeout(() => {
      this.setData({
        showBombAnimation: false
      });
    }, 1200);

    this.sendBomb();
  },

  // 检查登录状态
  checkLoginStatus() {
    const userInfo = wx.getStorageSync('userInfo');
    if (!userInfo) {
      // 用户未登录，跳转到登录页面
      wx.redirectTo({
        url: '/subpkg/pages/login/login'
      });
    }
  }

});



